home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2007 December / PCWKCD1207B.iso / Blogowanie poza sfera / Flock 1.0 beta / flock-1.0RC3.en-US.win32.exe / flock / components / flockLivejournalService.js < prev    next >
Text File  |  2007-10-18  |  29KB  |  839 lines

  1. // vim: ts=2 sw=2 expandtab cindent
  2. //
  3. // BEGIN FLOCK GPL
  4. //
  5. // Copyright Flock Inc. 2005-2007
  6. // http://flock.com
  7. //
  8. // This file may be used under the terms of of the
  9. // GNU General Public License Version 2 or later (the "GPL"),
  10. // http://www.gnu.org/licenses/gpl.html
  11. //
  12. // Software distributed under the License is distributed on an "AS IS" basis,
  13. // WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  14. // for the specific language governing rights and limitations under the
  15. // License.
  16. //
  17. // END FLOCK GPL
  18.  
  19. // CONTENTS OF THIS FILE:
  20. // This file contains the implementation of the LiveJournal service. This
  21. // involves the following components:
  22. //   flockLJService - the service class itself
  23. //   flockLJController - the controller class
  24. //   flockLJServiceFactory - factory object for flockLJService
  25. //   flockLJModule - module object for XPCOM registration
  26. //   flockLJAccount - the account class
  27.  
  28. const ENABLE_DEBUG = true; // switch to turn off slow debug code for production
  29. function DEBUG(x) { if (ENABLE_DEBUG) debug("flockLivejournalService: "+x+"\n"); }
  30.  
  31. const Cc = Components.classes;
  32. const Ci = Components.interfaces;
  33. const Cr = Components.results;
  34. const Cu = Components.utils;
  35.  
  36. const LIVEJOURNAL_CID        = Components.ID("{e642271b-1b0d-4d5d-ab51-34de23f75fc7}");
  37. const LIVEJOURNAL_CONTRACTID = "@flock.com/people/livejournal;1";
  38. const LIVEJOURNAL_TITLE      = "LiveJournal Web Service";
  39. const LIVEJOURNAL_FAVICON    = "http://www.livejournal.com/favicon.ico";
  40. const SERVICE_ENABLED_PREF          = "flock.service.livejournal.enabled";
  41. const CATEGORY_COMPONENT_NAME       = "LiveJournal JS Component"
  42. const CATEGORY_ENTRY_NAME           = "livejournal"
  43.  
  44. const RDFS  = Cc["@mozilla.org/rdf/rdf-service;1"].getService(Ci.nsIRDFService);
  45. const IOS   = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
  46. const RDFCU = Cc["@mozilla.org/rdf/container-utils;1"].getService(Ci.nsIRDFContainerUtils);
  47.  
  48. const OBS_TOPIC_XPCOMSHUTDOWN  = "xpcom-shutdown";
  49.  
  50. const FLOCK_NS = "http://flock.com/rdf#";
  51. const RDF_NS = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
  52. const RDF_TYPE = RDFS.GetResource(RDF_NS+"type");
  53. const COOP_TYPE = RDFS.GetResource(FLOCK_NS+"CoopType");
  54.  
  55. const COOP_CHROME_URL = "chrome://flock/content/common/coop.js";
  56.  
  57. var gCompTK;
  58. function getCompTK() {
  59.   if (!gCompTK) {
  60.     gCompTK = Components.classes["@flock.com/singleton;1"]
  61.                         .getService(Components.interfaces.flockISingleton)
  62.                         .getSingleton("chrome://browser/content/flock/services/common/load-compTK.js")
  63.                         .wrappedJSObject;
  64.   }
  65.   return gCompTK;
  66. }
  67.  
  68. var gTimers = [];  // For use with the scheduler
  69.  
  70. function loadSubScript(spec) {
  71.   var loader = Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader);
  72.   var context = {};
  73.   loader.loadSubScript(spec, context);
  74.   return context;
  75. }
  76.  
  77. var Coop = loadSubScript(COOP_CHROME_URL).Coop;
  78.  
  79. var loader = Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader);
  80. loader.loadSubScript("chrome://browser/content/utilityOverlay.js");
  81. loader.loadSubScript("chrome://flock/content/xmlrpc/xmlrpchelper.js");
  82. loader.loadSubScript("chrome://flock/content/blog/blogBackendLib.js");
  83.  
  84.  
  85. // String defaults... may be updated later through Web Detective
  86. var gStrings = {
  87.   "domains": "livejournal.com",
  88.   "userlogin": "http://www.livejournal.com/",
  89.   "userprofile": "http://%accountid%.livejournal.com/profile",
  90.   "editprofile": "http://www.livejournal.com/manage/profile/",
  91.   "userblog": "http://%accountid%.livejournal.com/",
  92.   "userfriends": "http://%accountid%.livejournal.com/friends",
  93.   "userphotos": "http://pics.livejournal.com/%accountid%",
  94.   "userpics": "http://www.livejournal.com/allpics.bml?user=%accountid%",
  95.   "postcomment": "http://fixme.com",
  96.   "userfoaf": "http://www.livejournal.com/users/%accountid%/data/foaf"
  97. };
  98.  
  99. // Helper function for LJ URLs - needs to be updated periodically
  100. function makeLiveJournalURL(aType, aFriendID) {
  101.   switch (aType) {
  102.     case "openProfile":
  103.       return gStrings["userprofile"].replace("%accountid%", aFriendID);
  104.     case "openBlog":
  105.       return gStrings["userblog"].replace("%accountid%", aFriendID);
  106.     case "viewFriends":
  107.       return gStrings["userfriends"].replace("%accountid%", aFriendID);
  108.     case "postComment":
  109.       return gStrings["postcomment"].replace("%accountid%", aFriendID);
  110.     case "openPhotos":
  111.       return gStrings["userphotos"].replace("%accountid%", aFriendID);
  112.     case "userpics":
  113.       return gStrings["userpics"].replace("%accountid%", aFriendID);
  114.     default:
  115.       return gStrings[aType].replace("%accountid%", aFriendID);
  116.   }
  117. }
  118.  
  119. function userBlogsListener(aListener) {
  120.   this.listener = aListener;
  121. }
  122.  
  123. userBlogsListener.prototype = {
  124.   // aResult is an Array (simpleEnumerator) of struct objects
  125.   onResult: function UBL_onResult(aResult) {
  126.     var result = new Array();
  127.     for (i=0; i<aResult.length; i++){
  128.       var entry = aResult[i];
  129.       var newAccount = new BlogAccount(entry.blogName);
  130.       newAccount.blogid = entry.blogid;
  131.       newAccount.apiLink = "";
  132.       newAccount.URL = entry.url;
  133.       result.push(newAccount);
  134.     }
  135.     this.listener.onResult(new simpleEnumerator(result));
  136.   },
  137.   onError: function UBL_onError(aErrorCode, aErrorMsg) {
  138.     var error = Cc['@flock.com/error;1'].createInstance(Ci.flockIError);
  139.     error.serviceErrorCode = aErrorCode;
  140.     error.serviceErrorString = aErrorMsg;
  141.     switch (aErrorCode) {
  142.       case 0:
  143.         // Invalid login/pass
  144.         error.errorCode = Ci.flockIError.BLOG_INVALID_AUTH;
  145.         break;
  146.       default:
  147.         // Unknown error code
  148.         error.errorCode = Ci.flockIError.BLOG_UNKNOWN;
  149.     }
  150.     this.listener.onError(null, "", error);
  151.   },
  152.   onFault: function UBL_onFault(aErrorCode, aErrorMsg) {
  153.     var error = Cc['@flock.com/error;1'].createInstance(Ci.flockIError);
  154.     error.serviceErrorCode = aErrorCode;
  155.     error.serviceErrorString = aErrorMsg;
  156.     switch (aErrorCode) {
  157.       case 0:
  158.         // Invalid login/pass
  159.         error.errorCode = Ci.flockIError.BLOG_INVALID_AUTH;
  160.         break;
  161.       default:
  162.         // Unknown error code
  163.         error.errorCode = Ci.flockIError.BLOG_UNKNOWN;
  164.     }
  165.     this.listener.onError(null, "", error);
  166.   }
  167. }
  168.  
  169.  
  170. // ================================================
  171. // ========== BEGIN flockLJService class ==========
  172. // ================================================
  173.  
  174. function flockLJService()
  175. {
  176.   /* Constructors of Adapter Services should ensure that they're
  177.   properly represented in the RDF.
  178.   Question: Should the Services all be children of a Services Root?
  179.  
  180.   TODO: Generalize this and make it declarative for every service
  181.   TODO: Add proper refresh intervals to all the object constructors,
  182.   */
  183.  
  184.   this.acUtils = Components.classes["@flock.com/account-utils;1"]
  185.                            .getService(Components.interfaces.flockIAccountUtils);
  186.  
  187.   this.obs = Components.classes["@mozilla.org/observer-service;1"]
  188.                        .getService(Components.interfaces.nsIObserverService);
  189.   this.obs.addObserver(this, OBS_TOPIC_XPCOMSHUTDOWN, false);
  190.  
  191.   this.status = Components.interfaces.flockIWebService.STATUS_UNKNOWN;
  192.   this.url = "http://www.livejournal.com";
  193.   this.initialized = false;
  194.  
  195.   // flockIBlogWebService
  196.   this.supportsCategories = 0;
  197.   this.supportsPostReplace = true;
  198.   this.metadataOverlay = "chrome://browser/content/flock/services/livejournal/ljBlogOverlay.xul";
  199.  
  200.   this._ctk = {
  201.     interfaces: [
  202.       "nsISupports",
  203.       "nsISupportsCString",
  204.       "nsIClassInfo",
  205.       "nsIObserver",
  206.       "flockIWebService",
  207.       "flockIBlogWebService",
  208.       "flockIManageableWebService",
  209.       "flockIPollingService"
  210.     ],
  211.     shortName: "livejournal",
  212.     fullName: "LiveJournal",
  213.     description: LIVEJOURNAL_TITLE,
  214.     favicon: LIVEJOURNAL_FAVICON,
  215.     CID: LIVEJOURNAL_CID,
  216.     contractID: LIVEJOURNAL_CONTRACTID,
  217.     accountClass: flockLJAccount
  218.   };
  219.   this._profiler = Cc["@flock.com/profiler;1"].getService(Ci.flockIProfiler);
  220.  
  221.   this.init();
  222. }
  223.  
  224.  
  225. // BEGIN nsIObserver interface
  226. flockLJService.prototype.observe =
  227. function flockLJService_observe(aSubject, aTopic, aState)
  228. {
  229.   switch (aTopic) {
  230.     case OBS_TOPIC_XPCOMSHUTDOWN:
  231.       this.obs.removeObserver(this, OBS_TOPIC_XPCOMSHUTDOWN);
  232.       break;
  233.   } // switch
  234. }
  235. // END nsIObserver interface
  236.  
  237.  
  238. // BEGIN flockIWebService interface
  239. flockLJService.prototype.addAccountById =
  240. function flockLJService_addAccountById(aAccountID, aIsTransient, aListener)
  241. {
  242.   DEBUG("{flockIWebService}.addAccountById('"+aAccountID+"', "+aIsTransient+", aListener)");
  243.   var ljAccountURN = "urn:flock:lj"+aAccountID;
  244.   var ljAccount = new this.faves_coop.Account(ljAccountURN, {
  245.     name: aAccountID,
  246.     serviceId: LIVEJOURNAL_CONTRACTID,
  247.     service: this.ljService,
  248.     accountId: aAccountID,
  249.     favicon: LIVEJOURNAL_FAVICON,
  250.     URL: 'http://www.livejournal.com/portal',
  251.     isPollable: false,
  252.     isTransient: aIsTransient
  253.   });
  254.   this.account_root.children.addOnce(ljAccount);
  255.   //this.USER = ljAccount.id();
  256.   //var acct = this.getAccount(ljAccount.id());
  257.  
  258.   this.USER = ljAccountURN;
  259.   // Add the blog(s)
  260.   var ljsvc = this;
  261.   var listener = {
  262.     onResult: function(aResult) {
  263.       ljsvc.logger.info("addAccountById: got the blog list from the server\n");
  264.       var theBlog;
  265.       while (aResult.hasMoreElements()) {
  266.         theBlog = aResult.getNext();
  267.         theBlog.QueryInterface(Components.interfaces.flockIBlogAccount);
  268.         theCoopBlog = new ljsvc.faves_coop.Blog(ljAccountURN+":"+theBlog.title, {
  269.           name: theBlog.title,
  270.           title: theBlog.title,
  271.           blogid: theBlog.blogid,
  272.           URL: theBlog.URL,
  273.           apiLink: 'http://www.livejournal.com/interface/xmlrpc'
  274.         });
  275.         ljAccount.children.addOnce(theCoopBlog);
  276.       }
  277.       if (aListener) aListener.onSuccess(acct, "addAccount");
  278.     },
  279.     onError: function addAcc_listener_onError(aSubject, aStatus, aError) {
  280.       ljsvc.faves_coop.accounts_root.children.remove(ljAccount);
  281.       ljAccount.destroy();
  282.       if (aListener) {
  283.         aListener.onError(aSubject, aStatus, aError);
  284.       }
  285.     }
  286.   }
  287.  
  288.   this.getUsersBlogs(listener, "");
  289.  
  290.   acct = this.getAccount(ljAccountURN);
  291.   return acct;
  292. }
  293.  
  294. flockLJService.prototype.logout =
  295. function flockLJService_logout()
  296. {
  297.   this.acUtils.removeCookies(this.webDetective.getSessionCookies("livejournal"));
  298.   this.USER = null;
  299. }
  300. // END flockIWebService interface
  301.  
  302.  
  303. // BEGIN flockIManageableWebService interface
  304. flockLJService.prototype.ownsDocument =
  305. function flockLJService_ownsDocument(aDocument)
  306. {
  307.   DEBUG("{flockIManageableWebService}.ownsDocument(aDocument)");
  308.   aDocument.QueryInterface(Components.interfaces.nsIDOMHTMLDocument);
  309.   var ios = Components.classes["@mozilla.org/network/io-service;1"]
  310.                       .getService(Components.interfaces.nsIIOService);
  311.   var uri = ios.newURI(aDocument.URL, null, null);
  312.   if ((uri.host.indexOf("livejournal.com") == 0) ||
  313.       (uri.host.indexOf(".livejournal.com") > 0))
  314.   {
  315.     if (uri.host.indexOf("adserver.livejournal.com") >= 0) {
  316.       return false;
  317.     } else {
  318.       return true;
  319.     }
  320.   }
  321.   return false;
  322. }
  323.  
  324. flockLJService.prototype.updateAccountStatusFromDocument =
  325. function flockLJService_updateAccountStatusFromDocument(aDocument)
  326. {
  327.   DEBUG("{flockIManageableWebService}.updateAccountStatusFromDocument()");
  328.   if (this.webDetective.detect("livejournal", "loggedout", aDocument, null)) {
  329.     this.acUtils.markAllAccountsAsLoggedOut(LIVEJOURNAL_CONTRACTID);
  330.   } else if (this.webDetective.detect("livejournal", "loggedin", aDocument, null)) {
  331.     var results = Components.classes["@mozilla.org/hash-property-bag;1"]
  332.                             .createInstance(Components.interfaces.nsIWritablePropertyBag2);
  333.     if (this.webDetective.detect("livejournal", "accountinfo", aDocument, results)) {
  334.       var accountID = results.getPropertyAsAString("accountid");
  335.       if (accountID && accountID.length) {
  336.         var accountURN = this.acUtils.getAccountURNById(this.urn, accountID);
  337.         this.acUtils.ensureOnlyAuthenticatedAccount(accountURN);
  338.         this.USER = accountURN;
  339.       }
  340.     }
  341.   }
  342. }
  343. // END flockIManageableWebService interface
  344.  
  345.  
  346. // BEGIN flockIBlogWebService interface
  347. flockLJService.prototype.parseUsersBlogs =
  348. function flockLJService_parseUsersBlogs(listener, inst)
  349. {
  350.   try {
  351.     debug("flockLJService.prototype.parseUsersBlogs\n");
  352.     var result = [];
  353.     var dom = inst._req.responseXML;
  354.     var domEntries = dom.getElementsByTagName("entry");
  355.  
  356.     if (domEntries.length > 0) { // Regular ATOM feed (ATOM)
  357.       for (var i = 0; i < domEntries.length; i++) {
  358.         debug("One entry...\n");
  359.         domEntry = domEntries[i];
  360.         title = domEntry.getElementsByTagName("title")[0].textContent;
  361.         var newAccount = new BlogAccount(title);
  362.         newAccount.api = this.shortName;
  363.         var links = domEntry.getElementsByTagName("link");
  364.         for (var j = 0; j < links.length; j++) {
  365.           var link = links[j]
  366.           switch (link.getAttribute("rel")) {
  367.             case "alternate":
  368.               newAccount.URL = link.getAttribute("href");
  369.               break;
  370.             case "http://schemas.google.com/g/2005#post":
  371.               newAccount.apiLink = link.getAttribute("href");
  372.               break;
  373.           }
  374.         }
  375.         result.push(newAccount);
  376.       }
  377.     }
  378.     else { // Just a list of links (Livejournal)
  379.       var links = dom.getElementsByTagName("link");
  380.       var result = [];
  381.       for (var i = 0; i < links.length; ++i) {
  382.         var link = links[i];
  383.         var title = link.getAttribute("title");
  384.         var rel = link.getAttribute("rel");
  385.         var href = link.getAttribute("href");
  386.         switch (rel) {
  387.           case "service.post":
  388.           {
  389.             href.match(/.+\/(.+)/);
  390.             var newAccount = new BlogAccount(title);
  391.             newAccount.api = this.shortName;
  392.             newAccount.blogid = RegExp.$1;
  393.             newAccount.apiLink = href;
  394.             newAccount.editLink = href;
  395.             result.push(newAccount);
  396.           }; break;
  397.           case "alternate":
  398.           {
  399.             for (j in result) {
  400.               if (result[j].title == title) {
  401.                 result[j].URL = href;
  402.               }
  403.             }
  404.           }; break;
  405.         }
  406.       }
  407.     }
  408.     debug("Found "+ result.length +" blogs\n");
  409.     listener.onResult(new simpleEnumerator(result));
  410.   }
  411.   catch(e) {
  412.     var logger = Components.classes['@flock.com/logger;1']
  413.                            .createInstance(Components.interfaces.flockILogger);
  414.     logger.init("livejournal");
  415.     logger.error(e + " " + e.lineNumber);
  416.     listener.onError(e + " " + e.lineNumber);
  417.   }
  418. }
  419.  
  420.  
  421. flockLJService.prototype.newPost =
  422. function flockLJService_newPost(aListener, aBlogId, aPost, aPublish, aNotifications)
  423. {
  424.   var svc = this;
  425.  
  426.   var coopBlog = this.faves_coop.get(aBlogId);
  427.   var coopAccount = coopBlog.getParent();
  428.  
  429.   var pw = this.acUtils.getPassword(this.urn+':'+coopAccount.accountId);
  430.  
  431.   var extra = [];
  432.   if (aPost.extra)
  433.     while (aPost.extra.hasMore())
  434.       extra.push(aPost.extra.getNext());
  435.  
  436.   var nocomments = (extra[2] == "0") ? false : true;
  437.   var notifsArray = [];
  438.  
  439.   var date = new Date();
  440.   var hours = date.getHours();
  441.   var month = date.getMonth() + 1;
  442.   var day = date.getDate();
  443.   var year = date.getFullYear();
  444.   var hour = date.getHours();
  445.   var min = date.getMinutes();
  446.  
  447.   var labels = [];
  448.   if (aPost.tags) {
  449.     while (aPost.tags.hasMore()) {
  450.       labels.push(aPost.tags.getNext());
  451.     }
  452.   }
  453.   var content = aPost.description.replace("</lj>", "", "gi");
  454.  
  455.   var listener = {
  456.     onResult: function(aResult) {
  457.       aListener.onResult(aResult);
  458.     },
  459.     onError: function(errorcode, errormsg) {
  460.       svc.logger.error("<<<<<<<<<< Livejournal: SERVER TO FLOCK\n");
  461.       svc.logger.error("FAULT "+errorcode+" "+errormsg+"\n");
  462.  
  463.       var error = Cc['@flock.com/error;1'].createInstance(Ci.flockIError);
  464.       error.serviceErrorCode = errorcode;
  465.       error.serviceErrorString = errormsg;
  466.       switch (errorcode) {
  467.         case 0: // Invalid login/pass
  468.           error.errorCode = Ci.flockIError.BLOG_INVALID_AUTH;
  469.           error.errorString = "Bad authentication";
  470.           break;
  471.         default: // Unknown error code
  472.           error.errorCode = Ci.flockIError.BLOG_UNKNOWN;
  473.           error.errorString = "Unknown Error";
  474.       }
  475.       aListener.onError(error);
  476.     },
  477.     onFault: function(errorcode, errormsg) {
  478.       svc.logger.error("<<<<<<<<<< Livejournal: SERVER TO FLOCK\n");
  479.       svc.logger.error("FAULT "+errorcode+" "+errormsg+"\n");
  480.  
  481.       var error = Cc['@flock.com/error;1'].createInstance(Ci.flockIError);
  482.       error.serviceErrorCode = errorcode;
  483.       error.serviceErrorString = errormsg;
  484.       switch (errorcode) {
  485.         case 0: // Invalid login/pass
  486.           error.errorCode = Ci.flockIError.BLOG_INVALID_AUTH;
  487.           error.errorString = "Bad authentication";
  488.           break;
  489.         default: // Unknown error code
  490.           error.errorCode = Ci.flockIError.BLOG_UNKNOWN;
  491.           error.errorString = "Unknown Error";
  492.       }
  493.       aListener.onFault(error);
  494.     }
  495.   };
  496.  
  497.   var xmlrpcServer = new flockXmlRpcServer(coopBlog.apiLink);
  498.   var args = [{username: coopAccount.accountId, password: pw.password,
  499.                subject: aPost.title, event: content,
  500.                security: extra[0], allowmask: extra[1], ver: 1,
  501.                year: year, mon: month, day: day, hour: hour, min: min,
  502.                // props: [{opts_nocomments: nocomments}],
  503.                props: {taglist: labels.join(','), opt_nocomments: nocomments}
  504.                }];
  505.   xmlrpcServer.call("LJ.XMLRPC.postevent", args, listener);
  506. }
  507.  
  508. flockLJService.prototype.editPost =
  509. function flockLJService_editPost(aListener, aBlogId, aPost, aPublish, aNotifications)
  510. {
  511.   var svc = this;
  512.  
  513.   var coopBlog = this.faves_coop.get(aBlogId);
  514.   var coopAccount = coopBlog.getParent();
  515.  
  516.   var pw = this.acUtils.getPassword(this.urn+':'+coopAccount.accountId);
  517.  
  518.   var labels = [];
  519.   if (aPost.tags) {
  520.     while (aPost.tags.hasMore()) {
  521.       labels.push(aPost.tags.getNext());
  522.     }
  523.   }
  524.   var content = aPost.description.replace("</lj>", "", "gi");
  525.   var extra = [];
  526.   if (aPost.extra) {
  527.     while (aPost.extra.hasMore()) {
  528.       extra.push(aPost.extra.getNext());
  529.     }
  530.   }
  531.   var nocomments = (extra[2] == "0") ? false : true;
  532.  
  533.   var notifsArray = [];
  534.  
  535.   var listener = {
  536.     onResult: function(aResult) {
  537.       aListener.onResult(aResult);
  538.     },
  539.     onError: function(error) {
  540.       svc.logger.error("<<<<<<<<<< LiveJournal API: SERVER TO FLOCK\n");
  541.       svc.logger.error("ERROR "+error+"\n");
  542.       aListener.onError(error);
  543.     },
  544.     onFault: function(error) {
  545.       svc.logger.error("<<<<<<<<<< LiveJournal API: SERVER TO FLOCK\n");
  546.       svc.logger.error("FAULT "+error+"\n");
  547.       aListener.onFault(error);
  548.     }
  549.   };
  550.  
  551.   var xmlrpcServer = new flockXmlRpcServer(coopBlog.apiLink);
  552.   var args = [{username: coopAccount.accountId,
  553.                password: pw.password,
  554.                itemid: aPost.postid,
  555.                subject: aPost.title,
  556.                event: content,
  557.                security: extra[0],
  558.                allowmask: extra[1],
  559.                ver: 1,
  560.                props:
  561.                  {
  562.                    taglist: labels.join(','),
  563.                    opt_nocomments: nocomments
  564.                  }
  565.               }];
  566.   xmlrpcServer.call("LJ.XMLRPC.editevent", args, listener);
  567. }
  568.  
  569. flockLJService.prototype.deletePost =
  570. function flockLJService_deletePost(aListener, aBlogId, aPostid)
  571. {
  572.   debug("***** flockLJService.deletePost: not supported!\n");
  573. }
  574.  
  575. flockLJService.prototype.getPost =
  576. function flockLJService(aListener, aBlogId, aPostid)
  577. {
  578.   debug("***** flockLJService.getPost: not supported!\n");
  579. }
  580.  
  581. flockLJService.prototype.getUsersBlogs =
  582. function flockLJService_getUserBlogs(aListener, aUrl)
  583. {
  584.   var username = this.faves_coop.get(this.USER).name;
  585.   debug("USER: "+username+"\n");
  586.   var pw = this.acUtils.getPassword(this.urn+':'+username);
  587.  
  588.   var listener = new userBlogsListener(aListener);
  589.   var xmlrpcServer = new flockXmlRpcServer("http://www.livejournal.com/interface/blogger");
  590.   var args = ["flockbrowser", username, pw.password];
  591.   xmlrpcServer.call("blogger.getUsersBlogs", args, listener);
  592. }
  593.  
  594. flockLJService.prototype.getRecentPosts =
  595. function flockLJService_getRecentPosts(aListener, aBlogId, aNumber)
  596. {
  597.   var svc = this;
  598.  
  599.   var coopBlog = this.faves_coop.get(aBlogId);
  600.   var coopAccount = coopBlog.getParent();
  601.  
  602.   var pw = this.acUtils.getPassword(this.urn+':'+coopAccount.accountId);
  603.  
  604.   var listener = {
  605.     onResult: function(aResult) {
  606.       var result = [];
  607.       svc.logger.info("<<<<<<<<<< LiveJournal API: SERVER TO FLOCK\n");
  608.       for (i=0; i<aResult.length; i++) {
  609.         var post = new BlogPost();
  610.         var content = aResult[i].content;
  611.         if (content.match(/<title.*>(.+?)</)) {
  612.           post.title = RegExp.$1;
  613.         }
  614.         post.issued = aResult[i].dateCreated.getTime();
  615.         post.postid = aResult[i].postId.split(":")[1];
  616.         result.push(post);
  617.       }
  618.  
  619.       // and return the data source through the listener
  620.       aListener.onResult(new simpleEnumerator(result));
  621.     },
  622.     onError: function(error) {
  623.       svc.logger.error("<<<<<<<<<< LiveJournal API: SERVER TO FLOCK\n");
  624.       svc.logger.error("ERROR "+error+"\n");
  625.       aListener.onError(error);
  626.     },
  627.     onFault: function(code, error) {
  628.       svc.logger.error("<<<<<<<<<< LiveJournal API: SERVER TO FLOCK\n");
  629.       svc.logger.error("FAULT #"+code+": "+error+"\n");
  630.       var flerror = Cc['@flock.com/error;1'].createInstance(Ci.flockIError);
  631.       flerror.serviceErrorCode = code;
  632.       flerror.serviceErrorString = error;
  633.       flerror.errorCode = Ci.flockIError.BLOG_UNKNOWN_ERROR;
  634.       flerror.errorString = "Unknown Error";
  635.  
  636.       aListener.onFault(flerror);// TODO: bubble up the error to the UI
  637.     }
  638.   }
  639.  
  640.   var xmlrpcServer = new flockXmlRpcServer("http://www.livejournal.com/interface/blogger");
  641.   // The username is used as the blogid for this call
  642.   var args = ['flockblog', coopAccount.accountId, coopAccount.accountId, pw.password, aNumber];
  643.   xmlrpcServer.call("blogger.getRecentPosts", args, listener);
  644. }
  645.  
  646. flockLJService.prototype.getCategoryList =
  647. function flockLJService_getCategoryList(aListener, aAccount)
  648. {
  649.   aListener.onResult(new simpleEnumerator([]));
  650. }
  651.  
  652. flockLJService.prototype.init =
  653. function flockLJService_init()
  654. {
  655.   DEBUG(".init()");
  656.   if (this.initialized) {
  657.     return;
  658.   }
  659.  
  660.   var evtID = this._profiler.profileEventStart("lj-init");
  661.  
  662.   this.prefService = Components.classes["@mozilla.org/preferences-service;1"]
  663.                                .getService(Components.interfaces.nsIPrefBranch);
  664.   if ( this.prefService.getPrefType(SERVICE_ENABLED_PREF) &&
  665.        !this.prefService.getBoolPref(SERVICE_ENABLED_PREF) )
  666.   {
  667.     DEBUG("Pref "+SERVICE_ENABLED_PREF+" set to FALSE... not initializing.");
  668.     var catMgr = Cc["@mozilla.org/categorymanager;1"].getService(Ci.nsICategoryManager);
  669.     catMgr.deleteCategoryEntry("wsm-startup", CATEGORY_COMPONENT_NAME, true);
  670.     catMgr.deleteCategoryEntry("flockWebService", CATEGORY_ENTRY_NAME, true);
  671.     return;
  672.   }
  673.  
  674.   // Logger
  675.   this.logger = Cc['@flock.com/logger;1'].createInstance(Ci.flockILogger);
  676.   this.logger.init("livejournal");
  677.  
  678.   this.faves = RDFS.GetDataSourceBlocking('rdf:flock-favorites');
  679.   this.faves_coop = Cc["@flock.com/singleton;1"]
  680.                     .getService(Ci.flockISingleton)
  681.                     .getSingleton("chrome://flock/content/common/load-faves-coop.js")
  682.                     .wrappedJSObject;
  683.   this.account_root = this.faves_coop.accounts_root;
  684.  
  685.   this.ljService = new this.faves_coop.Service(
  686.   'urn:livejournal:service', {
  687.     name: 'livejournal',
  688.     desc: 'The LiveJournal Service'
  689.   });
  690.   this.ljService.serviceId = LIVEJOURNAL_CONTRACTID;
  691.  
  692.   // Load Web Detective file
  693.   this.webDetective = this.acUtils.useWebDetective("livejournal.xml");
  694.   for (var s in gStrings) {
  695.     gStrings[s] = this.webDetective.getString("livejournal", s, gStrings[s]);
  696.   }
  697.   this.ljService.domains = gStrings["domains"];
  698.   this.ljService.loginURL = gStrings["userlogin"];
  699.  
  700.   this.urn = this.ljService.id();
  701.  
  702.   // Update auth states
  703.   if (this.webDetective.detectCookies("livejournal", "loggedout", null)) {
  704.     this.acUtils.markAllAccountsAsLoggedOut(LIVEJOURNAL_CONTRACTID);
  705.   }
  706.  
  707.   this.initialized = true;
  708.  
  709.   this._profiler.profileEventEnd(evtID, "");
  710. }
  711.  
  712. // END flockIBlogWebService interface
  713.  
  714. flockLJService.prototype.refresh =
  715. function flockLJService_refresh(aURN, aListener)
  716. {
  717. }
  718.  
  719. // ========== END flockLJService class ==========
  720.  
  721.  
  722.  
  723.  
  724. // ========== BEGIN XPCOM Module support ==========
  725.  
  726. function createModule(aParams) {
  727.   return {
  728.     registerSelf: function (aCompMgr, aFileSpec, aLocation, aType) {
  729.       aCompMgr = aCompMgr.QueryInterface(Ci.nsIComponentRegistrar);
  730.       aCompMgr.registerFactoryLocation( aParams.CID, aParams.componentName,
  731.                                         aParams.contractID, aFileSpec,
  732.                                         aLocation, aType );
  733.       var catMgr = Cc["@mozilla.org/categorymanager;1"]
  734.         .getService(Ci.nsICategoryManager);
  735.       if (!aParams.categories) { aParams.categories = []; }
  736.       for (var i = 0; i < aParams.categories.length; i++) {
  737.         var cat = aParams.categories[i];
  738.         catMgr.addCategoryEntry( cat.category, cat.entry,
  739.                                  cat.value, true, true );
  740.       }
  741.     },
  742.     getClassObject: function (aCompMgr, aCID, aIID) {
  743.       if (!aCID.equals(aParams.CID)) { throw Cr.NS_ERROR_NO_INTERFACE; }
  744.       if (!aIID.equals(Ci.nsIFactory)) { throw Cr.NS_ERROR_NOT_IMPLEMENTED; }
  745.       return { // Factory
  746.         createInstance: function (aOuter, aIID) {
  747.           if (aOuter != null) { throw Cr.NS_ERROR_NO_AGGREGATION; }
  748.           var comp = new aParams.componentClass();
  749.           if (aParams.implementationFunc) { aParams.implementationFunc(comp); }
  750.           return comp.QueryInterface(aIID);
  751.         }
  752.       };
  753.     },
  754.     canUnload: function (aCompMgr) { return true; }
  755.   };
  756. }
  757.  
  758. // NS Module entrypoint
  759. function NSGetModule(aCompMgr, aFileSpec) {
  760.   return createModule({
  761.     componentClass: flockLJService,
  762.     CID: LIVEJOURNAL_CID,
  763.     contractID: LIVEJOURNAL_CONTRACTID,
  764.     componentName: CATEGORY_COMPONENT_NAME,
  765.     implementationFunc: function (aComp) { getCompTK().addAllInterfaces(aComp); },
  766.     categories: [
  767.       { category: "wsm-startup", entry: CATEGORY_COMPONENT_NAME, value: LIVEJOURNAL_CONTRACTID },
  768.       { category: "flockWebService", entry: CATEGORY_ENTRY_NAME, value: LIVEJOURNAL_CONTRACTID }
  769.     ]
  770.   });
  771. }
  772.  
  773. // ========== END XPCOM module support ==========
  774.  
  775.  
  776.  
  777. // ================================================
  778. // ========== BEGIN flockLJAccount class ==========
  779. // ================================================
  780.  
  781. function flockLJAccount()
  782. {
  783.   this.acUtils = Components.classes["@flock.com/account-utils;1"]
  784.                            .getService(Components.interfaces.flockIAccountUtils);
  785.   this.service = Components.classes[LIVEJOURNAL_CONTRACTID]
  786.                            .getService(Components.interfaces.flockIWebService);
  787.   this.faves = RDFS.GetDataSourceBlocking("rdf:flock-favorites");
  788.   this._coop = Components.classes['@flock.com/singleton;1']
  789.                          .getService(Components.interfaces.flockISingleton)
  790.                          .getSingleton("chrome://flock/content/common/load-faves-coop.js")
  791.                          .wrappedJSObject;
  792.   this._ctk = {
  793.     interfaces: [
  794.       "nsISupports",
  795.       "flockIWebServiceAccount",
  796.       "flockIBlogWebServiceAccount"
  797.     ]
  798.   };
  799.   getCompTK().addAllInterfaces(this);
  800. }
  801.  
  802. // BEGIN flockIWebServiceAccount interface
  803. flockLJAccount.prototype.activate =
  804. function flockLJAccount_activate(aListener)
  805. {
  806.   DEBUG("{flockIWebServiceAccount}.activate()");
  807.   var acctCoopObj = this._coop.get(this.urn);
  808.   acctCoopObj.isPollable = true;
  809.   this.acUtils.ensureOnlyAuthenticatedAccount(this.urn);
  810. }
  811. // END flockIWebServiceAccount interface
  812.  
  813.  
  814. // BEGIN flockIBlogWebServiceAccount interface
  815. flockLJAccount.prototype.getBlogs =
  816. function flockLJAccount_getBlogs()
  817. {
  818.   DEBUG("{flockIBlogWebServiceAccount}.getBlogs()");
  819.   var blogsEnum = {
  820.     QueryInterface: function(iid) {
  821.       if (!iid.equals(Components.interfaces.nsISupports) &&
  822.           !iid.equals(Components.interfaces.nsISimpleEnumerator))
  823.       {
  824.         throw Components.results.NS_ERROR_NO_INTERFACE;
  825.       }
  826.       return this;
  827.     },
  828.     hasMoreElements: function() {
  829.       return false;
  830.     },
  831.     getNext: function() {
  832.     }
  833.   };
  834.   return blogsEnum;
  835. }
  836. // END flockIBlogWebServiceAccount interface
  837.  
  838. // ========== END flockLJAccount class ==========
  839.